package com.itheima.ydd.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.ydd.common.ResultData;
import com.itheima.ydd.dto.SysMenuVo;
import com.itheima.ydd.entity.SysMenu;
import com.itheima.ydd.mapper.SysMenuMapper;
import com.itheima.ydd.service.SysMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    @Autowired
    private SysMenuMapper sysMenuMapper;

    /**
     * 所有菜单---看结果最多三层
     *
     * @return
     */
    @Override
    public List<SysMenuVo> allData() {
        //先查看一级菜单--特点是父级编号pid=0
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysMenu::getPid, 0);
        //一级菜单也有多个
        List<SysMenu> sysMenulist1 = sysMenuMapper.selectList(lambdaQueryWrapper);
        List<SysMenuVo> sysMenuVoList1 = sysMenulist1.stream().map(sysMenu1 -> {
            //将对象拷贝到vo中---缺少下级List对象
            SysMenuVo sysMenuVo1 = new SysMenuVo();
            BeanUtils.copyProperties(sysMenu1, sysMenuVo1);
            //通过一级对象的id作为父编号即pid能查到多个二级对象
            Integer pid = sysMenu1.getId();
            List<SysMenu> listSysMenu2 = findListByPid(pid);
            //还要通过二级的对象的pid查询多个3级对象---既要填装下级list还要封装成vo
            List<SysMenuVo> listSysMenuVo2 = listSysMenu2.stream().map(sysMenu2 -> {
                //拷贝二级到vo
                SysMenuVo sysMenuVo2 = new SysMenuVo();
                BeanUtils.copyProperties(sysMenu2, sysMenuVo2);
                //拿到每个2级的id
                Integer pid2 = sysMenu2.getId();
                //通过2级id作pid查3级list--调用抽取的方法
                List<SysMenu> listByPid3 = findListByPid(pid2);
                //将3级list塞到2级vo---因为只能塞vo所以要拷贝后再塞(3级的lowlist是空的)
                List<SysMenuVo> listSysMenuVo3 = listByPid3.stream().map(sysMenu3 -> {
                    SysMenuVo sysMenuVo3 = new SysMenuVo();
                    BeanUtils.copyProperties(sysMenu3, sysMenuVo3);
                    return sysMenuVo3;
                }).collect(Collectors.toList());

                sysMenuVo2.setChildren(listSysMenuVo3);
                return sysMenuVo2;
            }).collect(Collectors.toList());

            //将二级的listVo塞到一级对象中
            sysMenuVo1.setChildren(listSysMenuVo2);

            return sysMenuVo1;
        }).collect(Collectors.toList());


        //最终返回3层包裹的vo对象
        return sysMenuVoList1;
    }
    /**
     * 删除
     * @param id
     * @return
     */
    @Override
    public ResultData delById(Integer id) {
        //通过id当作pid去查,查到对象说明有子分类不能删
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysMenu::getPid,id);
        List<SysMenu> sysMenuList = sysMenuMapper.selectList(lambdaQueryWrapper);
        if (ObjectUtil.isNotEmpty(sysMenuList)){
            return ResultData.error("有子分类不能删除");
        }
        //没有子分类直接删除
        sysMenuMapper.deleteById(id);

        return ResultData.ok("删除菜单成功","");
    }



    /**
     * 通过Pid查询多个Sysmenu对象[全部]--提取方法
     *
     * @param pid
     * @return
     */
    private List<SysMenu> findListByPid(Integer pid) {
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
        lambdaQueryWrapper1.eq(SysMenu::getPid, pid);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(lambdaQueryWrapper1);
        return sysMenus;
    }

    /**
     * 将一个列表sysMenuVoList按照正确的层级填充好
     * @param sysMenuVoList
     */
    @Override
    public  List<SysMenuVo> setAllinRightPlace(List<SysMenuVo> sysMenuVoList) {
////遍历整个列表---嵌套循环失败
//        for (SysMenuVo thisMenuVo : sysMenuVoList) {
//            //获取当前vo的id
//            Integer thisId = thisMenuVo.getId();
//            for (SysMenuVo targetMenuVo : sysMenuVoList) {
//                //如果当前的id与目标的pid一致,this为target上级,将target塞入this的下级列表
//                if (thisId==targetMenuVo.getPid()){
//                    //判断thisvo是否为空,为空则新建存入,不空则add
//                    if (thisMenuVo.getChildren().isEmpty()){
//                        List<SysMenuVo> list = new ArrayList<>();
//                        list.add(targetMenuVo);
//                        thisMenuVo.setChildren(list);
//                    }else {
//                        List<SysMenuVo> children = thisMenuVo.getChildren();
//                        children.add(targetMenuVo);
//                        thisMenuVo.setChildren(children);
//                    }
//                }
//               continue;
//            }
//        }
        //方法2,分层级查询再从最下层第三层一层一层set下级list
       //2.1找到一级列表--特点Pid=0
        List<SysMenuVo> menuVoList1NoList = findMenuByPidinList(0, sysMenuVoList);

        //通过一级的id作为pid找到列表中所有2级的菜单
        List<SysMenuVo> menuVoList1 = menuVoList1NoList.stream().map(menu1 -> {
            Integer id1 = menu1.getId();//获取一级id
            //通过id作为Pid查询列表中所有的子列表对象(没有下级list)---查到全部的二级列表对象
            List<SysMenuVo> menuVoList2NoList = findMenuByPidinList(id1, sysMenuVoList);
            //这些2级的列表既要将下级的列表存入list,自己也要存入到上级的list中
            List<SysMenuVo> menuVoList2 = menuVoList2NoList.stream().map(menuVo2 -> {
                Integer id2 = menuVo2.getId();
                List<SysMenuVo> menuVoList3 = findMenuByPidinList(id2, sysMenuVoList);
                //将3级列表塞到2级对象中
                menuVo2.setChildren(menuVoList3);

                return menuVo2;
            }).collect(Collectors.toList());
            //将二级的listVo塞到一级对象中
            menu1.setChildren(menuVoList2);

            return menu1;

        }).collect(Collectors.toList());

        //最终返回完成的一级list
return menuVoList1;
    }

    /**
     * 通过Pid查询多个Sysmenu对象[在List中]--提取方法
     * @param idAsPid
     * @param sysMenuVoList
     * @return
     */
    private List<SysMenuVo> findMenuByPidinList(Integer idAsPid,List<SysMenuVo> sysMenuVoList) {
        ArrayList<SysMenuVo> list = new ArrayList<>();
        for (SysMenuVo sysMenuVo : sysMenuVoList) {
            Integer pid = sysMenuVo.getPid();
            if (idAsPid.equals(pid)){//当Integer数值在 -128~127之外时==和!=会失效---只能用equals
                //如果上级的id和下级的id匹配说明找对了,把下级塞入列表
                list.add(sysMenuVo);
            }
        }
        //最终返回下级列表
        return list;
    }

}
